<template>
  <div>
    <img v-lazy-load="item" v-for="(item, index) in arr" :key="index" />
  </div>
</template>

<script setup lang="ts">
import type { Directive } from 'vue';

/**
 * 图片懒加载案例
 * 批量引入图片的方法：import.meta.glob 和 import.meta.globEager
 *      1. glob 是懒加载模式
 *         let modules = {
 *              'xxx':() => import('xxx')
 *         }
 *      2. globEager 静态加载 (已弃用)
 *         import xxx from 'xxx';
 */
// let imagesList = import.meta.glob('./images/*.*');
// imagesList['./images/sword1.png']().then((res) => {
//   console.log(res.default);
// });  // 懒加载

// let imagesList = import.meta.globEager('./images/*.*');  // 直接报错
// console.log(imagesList);

// 批量引入图片并渲染图片
let imagesList: Record<string, { default: string }> = import.meta.glob('./images/*.png', {
  eager: true
}); // 代替 import.meta.globEager
// imgSrc.value = imagesList['./images/sword1.png'].default;
let arr = Object.values(imagesList).map((v) => v.default); // Object.values 遍历对象 , map 遍历返回新数组

/**
 * 懒加载指令
 *   1.引入默认图片，并替换所有图片
 *   2.创建 IntersectionObserver 实例 ，被配置为监听根中一段给定比例的可见区域
 *   3.entries[0]参数详解：
 *        time: 可见性发生变化的时间，是一个高精度时间戳，单位为毫秒
 *        target: 被观察的目标元素，是一个DOM节点对象
 *        rootBounds: 容器元素的矩形区域的信息，getBoundingClientRect() 方法的返回值，如果没有容器元素（即直接相对于视口滚动），则返回null
 *        boundingClientRect: 目标元素的矩形区域的信息
 *        intersectionRect: 目标元素与视口（或容器元素）的交叉区域的信息
 *        intersectionRatio: 目标元素的可见比例，即 intersectionRect 占 boundClientRect 的比例，完全可见时为 1，完全不可见的时候小于等于0
 *        isIntersecting: 目标元素与交叉区域观察者对象的根相交，则返回 true.返回 false, 那么可以由此判断，变换是从交叉状态到非交叉状态。
 *   4.通过 intersectionRatio 进行判断那些是可见图片，并进行加载
 *   5.取消观察者 unobserve()
 */
const vLazyLoad: Directive<HTMLElement, string> = async (el: any, binding: any) => {
  const defaultImg = await import('./images/default.jpg'); // 返回一个promise对象
  el.src = defaultImg.default;
  const observer = new IntersectionObserver((entries) => {
    if (entries[0].isIntersecting && entries[0].intersectionRatio > 0) {
      setTimeout(() => {
        el.src = binding.value;
        observer.unobserve(el);
      }, 1000); // 1s 后加载
    }
  });
  observer.observe(el);
};
</script>

<style lang="scss" scoped>
img {
  display: block;
  width: 640px;
  height: 360px;
  margin-bottom: 10px;
}
</style>
